/*
 *  Copyright (c) 2023-2025 苏州棱镜七彩信息科技有限公司 (Suzhou PrismAurora Information Technology Co.,Ltd)
 *  sbom-generate is licensed under Mulan PSL v2.
 *  You can use this software according to the terms and conditions of the Mulan PSL v2.
 *  You may obtain a copy of Mulan PSL v2 at:
 *           http://license.coscl.org.cn/MulanPSL2
 *  THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
 *  See the Mulan PSL v2 for more details.
 * */
package com.ljqc.utils;

import java.io.File;
import java.io.IOException;
import java.lang.reflect.Modifier;
import java.net.JarURLConnection;
import java.net.URL;
import java.net.URLDecoder;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;
import java.util.ServiceLoader;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.stream.Collectors;
import java.util.stream.StreamSupport;

public final class ClassUtils {
    private ClassUtils() {

    }

    private static final Logger LOGGER = Logger.getLogger(ClassUtils.class.getName());

    /**
     * 获取指定接口的所有实现类的实例列表
     * 支持在JAR包中和开发环境中运行
     *
     * @param interfaceClass 接口类
     * @param <T>            接口类型
     * @return 实现类的实例列表
     */
    public static <T> List<T> getInstancesOfInterface(Class<T> interfaceClass) {
        List<T> instances = new ArrayList<>();
        // 用于记录已经处理过的类名，避免重复实例化
        List<String> processedClasses = new ArrayList<>();

        // 方法1：尝试使用ServiceLoader（如果实现了SPI）
        try {
            ServiceLoader<T> serviceLoader = ServiceLoader.load(interfaceClass);
            List<T> serviceInstances = StreamSupport.stream(serviceLoader.spliterator(), false)
                    .collect(Collectors.toList());
            if (!serviceInstances.isEmpty()) {
                LOGGER.log(Level.FINE, "通过ServiceLoader找到 {0} 个 {1} 的实现",
                        new Object[]{serviceInstances.size(), interfaceClass.getName()});
                // 记录已加载的类
                serviceInstances.forEach(instance ->
                        processedClasses.add(instance.getClass().getName()));
                instances.addAll(serviceInstances);
                return instances;
            }
        } catch (Exception e) {
            LOGGER.log(Level.FINE, "ServiceLoader加载失败", e);
        }

        // 方法2：扫描包路径查找实现类
        // 推断要扫描的包名列表
        List<String> packagesToScan = new ArrayList<>();
        // 1. 接口所在的实现包
        String basePackage = interfaceClass.getPackage().getName();
        String implPackage = basePackage.replace(".abs.", ".impl.");
        if (!implPackage.equals(basePackage)) {
            packagesToScan.add(implPackage);
        }
        // 2. 也可能直接放在同一个包下
        packagesToScan.add(basePackage);

        ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
        if (classLoader == null) {
            classLoader = ClassUtils.class.getClassLoader();
        }

        LOGGER.log(Level.FINE, "开始扫描包：{0}", packagesToScan);

        for (String packageName : packagesToScan) {
            try {
                String packagePath = packageName.replace('.', '/');
                Enumeration<URL> resources = classLoader.getResources(packagePath);

                while (resources.hasMoreElements()) {
                    URL resource = resources.nextElement();
                    LOGGER.log(Level.FINE, "找到资源：{0}", resource);

                    String protocol = resource.getProtocol();
                    if ("file".equals(protocol)) {
                        // 文件系统中的类
                        String filePath = URLDecoder.decode(resource.getFile(), StandardCharsets.UTF_8.name());
                        scanFileSystemClasses(
                                new File(filePath),
                                packageName,
                                interfaceClass,
                                instances,
                                processedClasses
                        );
                    } else if ("jar".equals(protocol)) {
                        // JAR包中的类
                        scanJarClasses(resource, packagePath, interfaceClass, instances, processedClasses);
                    }
                }
            } catch (IOException e) {
                LOGGER.log(Level.WARNING, "扫描包 " + packageName + " 时出错", e);
            }
        }

        LOGGER.log(Level.FINE, "找到 {0} 个 {1} 的实现",
                new Object[]{instances.size(), interfaceClass.getName()});

        return instances;
    }

    /**
     * 扫描文件系统中的类
     */
    private static <T> void scanFileSystemClasses(File directory, String packageName,
                                                  Class<T> interfaceClass, List<T> instances,
                                                  List<String> processedClasses) {
        if (!directory.exists() || !directory.isDirectory()) {
            LOGGER.log(Level.FINE, "目录不存在或不是目录：{0}", directory);
            return;
        }

        File[] files = directory.listFiles();
        if (files == null) {
            LOGGER.log(Level.FINE, "目录为空：{0}", directory);
            return;
        }

        for (File file : files) {
            if (file.isDirectory()) {
                // 递归扫描子目录
                String subPackageName = packageName + "." + file.getName();
                scanFileSystemClasses(file, subPackageName, interfaceClass, instances, processedClasses);
            } else if (file.getName().endsWith(".class")) {
                // 处理类文件
                String className = packageName + '.' + file.getName().substring(0, file.getName().length() - 6);
                processClass(className, interfaceClass, instances, processedClasses);
            }
        }
    }

    /**
     * 扫描JAR包中的类
     */
    private static <T> void scanJarClasses(URL resource, String packagePath,
                                           Class<T> interfaceClass, List<T> instances,
                                           List<String> processedClasses) {
        try {
            JarURLConnection jarConnection = (JarURLConnection) resource.openConnection();
            try (JarFile jarFile = jarConnection.getJarFile()) {
                Enumeration<JarEntry> entries = jarFile.entries();

                while (entries.hasMoreElements()) {
                    JarEntry entry = entries.nextElement();
                    String entryName = entry.getName();

                    // 检查条目是否属于目标包并且是.class文件
                    if (entryName.startsWith(packagePath) && entryName.endsWith(".class")) {
                        // 将路径转换为类名
                        String className = entryName.substring(0, entryName.length() - 6).replace('/', '.');
                        processClass(className, interfaceClass, instances, processedClasses);
                    }
                }
            }
        } catch (IOException e) {
            LOGGER.log(Level.WARNING, "扫描JAR包失败", e);
        }
    }

    /**
     * 处理单个类，检查是否是接口的实现
     */
    private static <T> void processClass(String className, Class<T> interfaceClass,
                                         List<T> instances, List<String> processedClasses) {
        // 检查是否已经处理过该类，避免重复实例化
        if (processedClasses.contains(className)) {
            LOGGER.log(Level.FINE, "类 {0} 已经处理过，跳过", className);
            return;
        }

        try {
            Class<?> clazz = Class.forName(className);
            // 添加到已处理列表
            processedClasses.add(className);

            // 检查是否是接口的实现类
            boolean isImplementation = interfaceClass.isAssignableFrom(clazz)
                    && !clazz.isInterface()
                    && !Modifier.isAbstract(clazz.getModifiers());

            if (isImplementation) {
                LOGGER.log(Level.FINE, "找到实现类：{0}", className);
                try {
                    @SuppressWarnings("unchecked")
                    T instance = (T) clazz.getDeclaredConstructor().newInstance();
                    instances.add(instance);
                    LOGGER.log(Level.FINE, "成功实例化：{0}", className);
                } catch (Exception e) {
                    LOGGER.log(Level.WARNING, "实例化类 " + className + " 失败", e);
                }
            }
        } catch (ClassNotFoundException e) {
            LOGGER.log(Level.FINE, "找不到类 " + className, e);
        } catch (NoClassDefFoundError e) {
            LOGGER.log(Level.FINE, "类定义错误 " + className, e);
        } catch (Exception e) {
            LOGGER.log(Level.WARNING, "处理类 " + className + " 时出错", e);
        }
    }
}
